﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureBeamEndTypeBehavior.h"
#include "StructureBasicBeam.h"
#include "StructureInstanceEndType.h"

#include "IInstance.h"
#include "IGraphicsElementShape.h"
#include "IBody.h"
#include "IPlane.h"
#include "IGraphicsBRepFace.h"
#include "AlgorithmBodyTopologyOperate.h"
#include "StructureInstanceUtils.h"
#include "GraphicsNodeUtils.h"
#include "DbObjectUtils.h"
#include "IGraphicsBRepBody.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;

DBOBJECT_DATA_DEFINE(StructureBeamEndTypeBehavior)
{
    m_pOwnerElement = nullptr;
}

StructureBeamEndTypeBehavior::StructureBeamEndTypeBehavior(IElement *pInstance)
{
    m_pOwnerElement = pInstance;
}

bool StructureBeamEndTypeBehavior::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    return true;
}

IInstance* StructureBeamEndTypeBehavior::GetOwnerInstance() const
{
    return quick_cast<IInstance>(m_pOwnerElement);
}

NdbObject* StructureBeamEndTypeBehavior::GetTopOwnerObject() const
{
    return nullptr;
}

void StructureBeamEndTypeBehavior::ReportInputDataIds(std::vector<RegenDataId>& oInputDataIds) const
{
    const IInstance* pInstance = GetOwnerInstance();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    const StructureBasicBeam* pBeam = StructureBasicBeam::Get(pInstance);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pBeam, L"pBeam为空",L"GDMPLab",L"2024-03-30");

    oInputDataIds.push_back(pBeam->GetStartEndFaceSectionTypeRdId());
}

OwnerPtr<IGraphicsElementShape> StructureBeamEndTypeBehavior::Customize(OwnerPtr<IGraphicsElementShape> opGRep) const
{
    IInstance* pInstance = GetOwnerInstance();
    DBG_WARN_AND_RETURN_UNLESS(pInstance, opGRep, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInstance->GetDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc, opGRep, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    const StructureBasicBeam* pBeam = StructureBasicBeam::Get(pInstance);
    DBG_WARN_AND_RETURN_UNLESS(pBeam, opGRep, L"pBeam为空",L"GDMPLab",L"2024-03-30");

    InstanceEndType sectionType = pBeam->GetStartEndFaceSectionType();
    if (sectionType == InstanceEndType::PerpendicularToAxis)
        return opGRep;

    // 获取起止控制点
    std::vector<Vector3d> startEndPts = StructureInstanceUtils::GetInstanceControlPoints(pInstance);
    DBG_WARN_AND_RETURN_UNLESS(startEndPts.size() == 2, opGRep, L"startEndPts无效",L"GDMPLab",L"2024-03-30");

    // 水平梁无需切端面
    if (MathUtils::IsEqual(startEndPts[0].Z(), startEndPts[1].Z(), Constants::LENGTH_EPS))
        return opGRep;

    // 获取Body
    std::vector<const IGraphicsBRepBody*> bodies;
    std::vector<Matrix4d> transforms;
    // TODO: 接口
    GraphicsNodeUtils::CollectBRepBodies(pInstance->GetDocument(), opGRep.get(), &bodies, &transforms);
    DBG_WARN_AND_RETURN_UNLESS(bodies.size() == 1 && transforms.size() == 1, opGRep, L"Body应该只有一个",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IGraphicsBRepBody> opBody = TransferOwnershipCast<IGraphicsBRepBody>(bodies.front()->Clone());
    DBG_WARN_AND_RETURN_UNLESS(opBody.get(), opGRep, L"opBody为空",L"GDMPLab",L"2024-03-30");
    opBody->Transform(transforms.front());
    IBody* pBody = opBody->GetGeometryFW();
    DBG_WARN_AND_RETURN_UNLESS(pBody, opGRep, L"pBody为空",L"GDMPLab",L"2024-03-30");

    // 获取起止切面
    std::vector<OwnerPtr<IPlane>> opSectionPlanes = StructureInstanceUtils::GetBasicBeamStartEndSectionPlanes(startEndPts[0], startEndPts[1], sectionType);
    DBG_WARN_AND_RETURN_UNLESS(opSectionPlanes.size() == 2, opGRep, L"opSectionPlanes为空",L"GDMPLab",L"2024-03-30");

    // 获取起止端面
    std::vector<IGraphicsBRepFace*> startEndFaces = StructureInstanceUtils::GetBasicBeamStartEndFaces(opBody.get(), startEndPts[0], startEndPts[1]);
    DBG_WARN_AND_RETURN_UNLESS(startEndFaces.size() == 2, opGRep, L"startEndFaces为空",L"GDMPLab",L"2024-03-30");

    bool bOk = AlgorithmBodyTopologyOperate::FitBodyToTargetedFaceWithoutTopoChange(opSectionPlanes[0].get(), pBody, startEndFaces[0]->GetGmFaceFW(), false);

    bOk = AlgorithmBodyTopologyOperate::FitBodyToTargetedFaceWithoutTopoChange(opSectionPlanes[1].get(), pBody, startEndFaces[1]->GetGmFaceFW(), false);

    OwnerPtr<IGraphicsElementShape> opNewGRep = IGraphicsElementShape::Create(opGRep->GetRenderLayer());
    opNewGRep->AddChild(TransferOwnership(opBody));
    Box3d newGrepBox = GraphicsNodeUtils::CalculateGraphicsNodeBoundingBox(pDoc, opNewGRep.get());
    opNewGRep->SetBox(newGrepBox);
    return opNewGRep;
}
